﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

//

/// \file GnufProgressBar.h
/// \brief Gnuf进度条
#pragma once
#include "GnufExtension.h"
#include <IProgressObserver.h>

namespace gnuf {
    class Bulletin;
}

namespace gnuf
{
    /// \brief Gnuf进度条，用以展示当前复杂操作的进度
    /// \see IProgressObserver
    class GNUF_EXTENSION_EXPORT GnufProgressBar final
        : public gcmp::IProgressObserver
    {
    public:
        static bool s_bAlreadyHaveOneBar;
        // If bWithReporter = true, create a gcmp::IProgressReporter when 
        // started. And then, respond automatically to this reporter's progress,
        // intead of explicitly calling setValue() method.
        /// \brief Gnuf进度条的构造函数，用来构造条状进度展示控件
        /// \param bWithReporter 是否带进度报告器，默认为true，自动响应进度，不需要手动调用setValue()来设置进度
        /// \param minimum 进度条的下限，默认为0
        /// \param maximum 进度条的上限，默认为100
        /// \param text 进度条的显示的信息
        GnufProgressBar(
            const bool bWithReporter = true,
            int minimum = 0, int maximum = 100,
            const std::wstring & text = L"");

        /*
        +---------------------------------------+
        |          ____________________         | .....
        |         |____DOING___WHAT____|        | 1th Section -> doingWhat
        |               _________               | .....
        |              /         \              |
        |             /           \             |
        |            (     30%     )            | 2th Section -> minimum, maximu, value
        |             \           /             |
        |              \_________/              |
        |              ___________              | .....
        |             |__MESSAGE__|             | 3rd Section -> message
        |          ___________________          | .....
        |         |______CAROUSEL_____|         | 4th Section -> carouselInterval, carouselData
        |     ______________________________    | .....
        |    |___________MINUTIAE___________|   | 5th Section -> minutiae
        |  ______             ________________  | .....
        | |_TIPS_|           |_CANCEL/CONFIRM_| | 6th Section -> helpCaption, helpHyperlink, cancelable, waitForConfirmingAfterFinished
        +---------------------------------------+ .....
        */
        /// \brief 维护一组参数，用于构造复杂的进度条
        struct GNUF_EXTENSION_EXPORT Parameters {
            Parameters() {}
            Parameters(const Parameters &);
            Parameters& operator=(const Parameters & that)
            {
                this->doingWhat                         = that.doingWhat;
                this->minimum                           = that.minimum;
                this->maximum                           = that.maximum;
                this->value                             = that.value;
                this->format                            = that.format;
                this->message                           = that.message;
                this->carouselFrameDisplayTime          = that.carouselFrameDisplayTime;
                this->carouselFrames                    = that.carouselFrames;
                this->minutiae                          = that.minutiae;
                this->helpCaption                       = that.helpCaption;
                this->helpHyperlink                     = that.helpHyperlink;
                this->cancelable                        = that.cancelable;
                this->allowToCancel                     = that.allowToCancel;
                this->waitForConfirmingAfterFinished    = that.waitForConfirmingAfterFinished;
                this->wantToStayOnTop                   = that.wantToStayOnTop;
                return *this;
            };
            /// \brief 定义轮播位的类型
            /// \details 一个轮播位由若干个片段组成
            /// - pair.first 存放了一个布尔值，用于标识该片段是图片还是文字，true为文字，false为图片
            /// - pair.second 存放了一个宽字符，对应着该片段的资源路径或文字内容
            typedef typename std::vector< std::pair<
                bool,                               // isText or isImage
                std::wstring                        // Text or Image
                > > CarouselFrameSections;

            /// \brief 定义一组轮播位对象
            /// \details 一组轮播位对象交替显示可以实现轮播的视觉效果
            /// - pair.first 存放一个布尔值，用于标识该轮播位是否为纯图片，false表示该轮播位没有文字，只有图片
            typedef typename std::vector< std::pair<
                bool,                               // isCaption or isImage
                Parameters::CarouselFrameSections   // Text or Image
                > > CarouselFrames;
            // 1st Section ////////////////////////////////////////////////////
            /// \brief 显示正在处理的事项
            std::wstring doingWhat;
            // 2nd Section ////////////////////////////////////////////////////
            /// \brief 进度条的下限
            int minimum = 0;
            /// \brief 进度条的上限
            int maximum = 100;
            /// \brief 进度条当前的数值
            int value = 0;
            /// \brief 进度显示的格式，0表示百分数， 1表示数值，2表示分数
            std::uint8_t format = 0; // 0:percentage, 1:value, 2:mode
            // 3rd Section ////////////////////////////////////////////////////
            /// \brief 进度条的信息，一般用来描述细分过程
            std::wstring message;
            // 4th Section ////////////////////////////////////////////////////
            bool doesCarouselSwitchFrameAutomatically()     const { return this->carouselFrameDisplayTime > 0; }
            bool doesCarouselSwitchFrameWhenValueChanged()  const { return this->carouselFrameDisplayTime < 1; }
            /// \brief 轮播位的刷新时间
            int carouselFrameDisplayTime = 0; // milliseconds
            /// \brief 一组轮播位
            Parameters::CarouselFrames carouselFrames;
            // 5th Section ////////////////////////////////////////////////////
            /// \brief 细节信息（单行或多行）
            std::vector< std::wstring > minutiae;
            // 6th Section ////////////////////////////////////////////////////
            /// \brief 帮助信息
            std::wstring helpCaption;
            /// \brief 帮助信息超链接
            std::wstring helpHyperlink;
            bool cancelable = false;
            std::function<bool()> allowToCancel = nullptr;
            bool waitForConfirmingAfterFinished = false;
            // Other Options //////////////////////////////////////////////////
            bool wantToStayOnTop = false;
        };
        /// \brief Gnuf进度条的构造函数，用来构造面板状进度展示控件
        /// \param parameters 存放进度条参数的结构体
        /// \param bWithReporter 是否带进度报告器，默认为true，自动响应进度，不需要手动调用setValue()来设置进度
        /// \see GnufProgressBar::Parameters
        GnufProgressBar(const GnufProgressBar::Parameters & parameters, const bool bWithReporter = true);
        ~GnufProgressBar();

        // Start the progress. If not idle, this method does nothing.
        // If the work is not nullptr, do this work on a separate thread.
        /// \brief 开始进度条，如果系统不处在空闲状态，不进行任何操作
        /// \param work 将工作函数放到子线程中运行
        /// \param handler 子线程中的函数退出后，主线程的响应函数
        void start(const std::function<void()> & work = nullptr);

        /// \return Return true, if started.
        /// \see start()
        bool isProgressing() const { return m_progressing; }
        
        // start child progress reporter, 
        // reflect the span between "start" and "end" on topReporter
        /// \brief 开启子进度报告器
        /// \details 与endChildProgress 配套使用，子进度报告器的进度会换算为父进度报告器的进度
        /// \param start 子进度报告器区间起点
        /// \param end 子进度报告器的区间终点
        /// \see endChildProgress
        void beginChildProgress(double start, double end);

        // end child progress reporter
        /// \brief 结束子进度报告器
        /// \details 与beginChildProgress 配套使用，开启了子进度报告器，必须在使用后关闭
        /// \see beginChildProgress
        void endChildProgress();
        
        // Set/Get if want to begin child progress report. By default, it is true. 
        // If false, the caller has to call beginChildProgress/endChildProgress.
        void setWantAutoChildProgressReport(bool val) { m_wantAutoChildProgressReport = val; }
        bool wantAutoChildProgressReport() const { return m_wantAutoChildProgressReport; }

        // Finish the progress. If not idle, this method does nothing.
        /// \brief 结束进度条
        void finish();
        
        // Set/Get the text and icon that intend to present the result once
        // finished. By defult, no any text or icon is presented.
        void setResultText(const std::wstring & text) { m_text = text; }
        const std::wstring & resultText() const { return m_text; }
        void setResultIcon(const std::wstring & icon) { m_icon = icon; }
        const std::wstring & resultIcon() { return m_icon; }
        void setResult(const std::wstring & icon, const std::wstring & text)
        {
            m_text = text;
            m_icon = icon;
        }
        
        // Set what is doing.
        void setDoingWhat(const std::wstring &);

        // Set one value in the range.
        void setValue(int);
        int value() const;

        int minimum() const;
        int maximum() const;

        // Set the message.
        void setMessage(const std::wstring &);

        // Set the minutiae.
        void setMinutiae(const std::vector< std::wstring > &);

        // Return true, if canceled through the UI by the user. Otherwise, return false.
        // If you allow the user to cancel, please set Parameters.cancelable = true.
        bool isCanceled() const;

        void setProgressBarText(const std::wstring &);

    protected:
        // Inherits from gcmp::IProgressObserver...
        virtual void ProgressChanged(gcmp::IProgressReporter *) override;

    private:
        void initialize();
        void showResult();
        void setDefaultProgressBarVisible(bool);

        gcmp::OwnerPtr<gnuf::Bulletin> m_bulletin;
        const bool m_bWithReporter;
        gcmp::OwnerPtr< gcmp::IProgressReporter > m_opTopReporter;

        //是否自动生成子进程报告器
        bool m_wantAutoChildProgressReport = true;

        std::wstring m_text;
        std::wstring m_icon;

        bool m_progressing = false; // not started, by default
    };
}
//_____________________________________________________________________________
// Declare a progress bar.
#define GNUF_PROGRESSBAR_DECLARE(progressbar, parameters, ...) \
    gcmp::OwnerPtr<GnufProgressBar> progressbar = NEW_AS_OWNER_PTR(\
        gnuf::GnufProgressBar, parameters, __VA_ARGS__ );
//_____________________________________________________________________________
// Implement the progress bar.
#define GNUF_PROGRESSBAR_IMPLEMENTATION_BEGIN(progressbar) \
    int progressbar##_work_error_code_ = 0; \
    const std::function<void()> progressbar##_work_ = [&]()->void
#define GNUF_PROGRESSBAR_IMPLEMENTATION_END(progressbar) \
    ;
//_____________________________________________________________________________
// Exectute the progress bar.
#define GNUF_PROGRESSBAR_EXECUTION_BEGIN(progressbar, synchronously) \
    if (nullptr == progressbar##.get()) \
    { \
        /* If no progress bar, work immediately. */ \
        progressbar##_work_(); \
    } \
    else \
    { \
        if ( synchronously ) \
        { \
            /* Progress, synchronously with doing the work. */ \
            progressbar##->start(); \
            progressbar##_work_(); \
        } \
        else \
        { \
            /* Progress, asynchronously with doing the work. */ \
            progressbar##->start( progressbar##_work_ ); \
        } \
    }
#define GNUF_PROGRESSBAR_EXECUTION_END(progressbar) \
    if (nullptr != progressbar##.get()) \
    { \
        progressbar##->finish(); \
    }
#define GNUF_PROGRESSBAR_EXECUTE(progressbar, synchronously) \
    GNUF_PROGRESSBAR_EXECUTION_BEGIN(progressbar, synchronously) \
    GNUF_PROGRESSBAR_EXECUTION_END(progressbar)
//_____________________________________________________________________________
// Stop the executing progress bar.
#define GNUF_PROGRESSBAR_STOP(progressbar) \
    return;
#define GNUF_PROGRESSBAR_STOP_WITH_ERROR_CODE(progressbar, errorcode) \
    progressbar##_work_error_code_ = errorcode; \
    return;
//_____________________________________________________________________________
// Check the result that the progress bar returns.
#define GNUF_PROGRESSBAR_ERROR_CODE(progressbar) \
    ( progressbar##_work_error_code_ )
#define GNUF_PROGRESSBAR_IS_TRUE(progressbar) \
    ( 0 == progressbar##_work_error_code_ )
#define GNUF_PROGRESSBAR_IS_FALSE(progressbar) \
    ( 0 != progressbar##_work_error_code_ )

#pragma region 线程强化的进度条
/// \brief 创建一个进度条，支持把任务放到子线程中
/// \param progressbar 进度条的变量名
/// \param 创建进度条时用到的参数
/// \see GnufProgressBar::Parameters
#define GNUF_PROGRESSBOARD_WITH_THREADWORKER(progressbar, parameter) \
gcmp::OwnerPtr<gnuf::GnufProgressBar> progressbar = NEW_AS_OWNER_PTR(\
        gnuf::GnufProgressBar, parameter, false );

/// \brief 创建一个进度条，支持把任务放到子线程中
/// \param progressbar 进度条的变量名
/// \param minimum 进度条的下限
/// \param maximum 进度条的上限
/// \param text 进度条前的文字信息
#define GNUF_PROGRESSBAR_WITH_THREADWORKER(progressbar, minimum, maximum, text) \
gcmp::OwnerPtr<gnuf::GnufProgressBar> progressbar = NEW_AS_OWNER_PTR(\
        gnuf::GnufProgressBar, false, minimum, maximum, text);

/// \brief 开启进度条，并执行子线程的任务
/// \param progressbar 已经创建的进度条变量名
#define GNUF_PROGRESSBAR_EXEC(progressbar, work) \
if (nullptr != progressbar.get()) \
{ \
    progressbar->start((work)); \
    progressbar->finish(); \
}
#pragma endregion 线程强化的进度条
